/*Copyright (C) 2009 - 2011 Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

/**********************************************************
** Format du fichier de niveau :
*** Un fichier peut contenir plusieurs niveaux
*** Un niveau dans un fichier fait 22 lignes séparée par des '\n'
*** Les deux première lignes sont l'en-tête du niveau :
**** La première est le nom du niveau (sur 50 caractères)
**** La deuxième est le nom de l'auteur (sur 50 caractères)
*** Les 20 dernière lignes contiennent le niveau sur 50 colonnes. On a:
**** ' ' : Une case vide
**** '#' : Un mur
**** 'O' : Un trou (autant que de caisses)
**** 'C' : Une caisse (autant que de trou)
**** 'J' : La position initiale du joueur (Un par niveau, ni plus ni moins)
**********************************************************/
# define POU_FVIDE    ' '
# define POU_FMUR     '#'
# define POU_FTROU    'O'
# define POU_FCAISSE  'C'
# define POU_FJOUEUR  'J'

/* Parse un fichier dans le but d'initialiser la matrice
** et les info sur la partie. Cette fonction n'initialise que
** les membres nb_caisses et nb_caisses_restantes de inf.
** \param file   Le fichier de pack de niveaux (ouvert)
** \param level  Le level à charger
** \param matrix La matrice à initialiser (allouée)
** \param inf    Les informations sur la partie (allouées)
** \return       0 en cas de succès
**               1 en cas d'une erreur de parsage
*/

#include "../headers.h"

int pou_get_case_t_char(POU_CASE_T ct) {
	switch(ct) {
	case POU_VIDE:
		return POU_FVIDE;
		break;
	case POU_MUR:
		return POU_FMUR;
		break;
	case POU_TROU:
		return POU_FTROU;
		break;
	case POU_CAISSE:
		return POU_FCAISSE;
		break;
	case POU_JOUEUR:
		return POU_FJOUEUR;
		break;
	default:
		Log_full(LOG_POUSSECAISSE , "pou_get_case_t_char : Type de case inconnu", ct);
		return POU_FVIDE;
		break;
	}
}

int pou_parse_file(FILE *file, int level, POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf) {
	int i, x, y;
	int nb_joueur = 0;
	char buffer[64];

	/* Déplacement en début de niveau */
	rewind(file);

	for(i = 0; i < ((level - 1) * 22) + 2; i++) {
		if(fgets(buffer, 53, file) == NULL) {
			return 1;
		}

		if(strlen(buffer) > 52) {
			return 1;
		}
	}

	/* parsage du niveau */
	for(y = 0; y < POU_MAT_Y; y++) {
		if(fgets(buffer, 53, file) == NULL) {
			return 1;
		}

		remove_ret_line(buffer);

		if(strlen(buffer) > 50) {
			return 1;
		}

		for(x = 0; x < POU_MAT_X; x++) {
			switch(buffer[x]) {
			case POU_FCAISSE:
				inf->nb_caisses++;
				inf->nb_caisses_restantes++;
				matrix[x][y] = POU_CAISSE;
				break;
			case POU_FJOUEUR:
				inf->pos_joueur.x = x;
				inf->pos_joueur.y = y;
				nb_joueur++;
				matrix[x][y] = POU_JOUEUR;
				break;
			case POU_FMUR:
				matrix[x][y] = POU_MUR;
				break;
			case POU_FTROU:
				inf->nb_trous++;
				matrix[x][y] = POU_TROU;
				break;
			case POU_FVIDE:
				matrix[x][y] = POU_VIDE;
				break;
			default:
				return 1;
				break;
			}
		}
	}

	if(inf->nb_caisses != inf->nb_trous || nb_joueur != 1) {
		return 1;
	}

	return 0;
}

/* Permet de parser un fichier de pack de niveau dans le but
** d'en retirer la liste des niveaux et la liste des auteurs
** NOTE: Les arguments lvl_list et author_list sont modifiés
**       et allouées par la fonction. Il faudra les libérer
**       après usage.
** \param file        Le fichier de pack de niveaux (ouvert)
** \param lvl_list    Un pointeur sur une chaine de caractère où
**                    sera stockée la liste des niveaux. La chaine
**                    sera allouée au fur et à mesure.
**                    /!\ à libérer après utilisation.
** \param author_list Un poiteur sur une chaine de caractère où
**                    sera stockée la liste des auteurs. La chaine
**                    sera allouée au fur et à mesure.
**                    /!\ à libérer après utilisation.
** \return            1 en cas d'erreur de parsage
**                    0 si tout s'est bien passé.
*/
int pou_get_level_list(FILE *file, char **lvl_list, char **author_list) {
	int i = 1, nb_author = 0, nb_name = 0;
	char line[64];

	while(fgets(line, 64, file) != NULL) {
		remove_ret_line(line);

		if(strlen(line) > 50 || strlen(line) == 0) {
			mfree(*lvl_list);
			mfree(*author_list);
			return 0;
		}
		else if(i % 22 == 1) {
			nb_name++;
			cat_line_in_entry(lvl_list, line);
		}
		else if(i % 22 == 2) {
			nb_author++;
			cat_line_in_entry(author_list, line);
		}

		i++;
	}

	if(nb_name != nb_author) {
		mfree(*lvl_list);
		mfree(*author_list);
		return 0;
	}

	return nb_name;
}

/* Permet de sauvegarder un niveau dans un fichier
** à partir de sa matrice.
*/
void pou_save_level(FILE *level_file, POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], const char *author_name, const char *level_name) {
	int x, y;

	fputs(level_name, level_file);
	fputc('\n', level_file);
	fputs(author_name, level_file);
	fputc('\n', level_file);

	for(y = 0; y < POU_MAT_Y; y++) {
		for(x = 0; x < POU_MAT_X; x++) {
			fputc(pou_get_case_t_char(matrix[x][y]), level_file);
		}
		fputc('\n', level_file);
	}
}

char *pou_level_to_string(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], const char *author, const char *name) {
	size_t len = 0, i, x, y;
	char *str;

	len = strlen(author) + strlen(name) + 2 + (POU_MAT_X + 1) * POU_MAT_Y;
	str = malloc((len + 1) * sizeof(*str));
	if(str != NULL) {
		str[0] = '\0';
		strcat(str, name);
		strcat(str, "\n");
		strcat(str, author);
		strcat(str, "\n");
		i = strlen(str);
		for(y = 0; y < POU_MAT_Y; y++) {
			for(x = 0; x < POU_MAT_X; x++) {
				str[i] = pou_get_case_t_char(matrix[x][y]);
				i++;
			}
			str[i] = '\n';
			i++;
		}
		str[i] = '\0';
	}
	return str;
}

/* Permet d'initialiser la matice et les informations
** sur la partie avec les données par défaut
*/
void pou_init_to_default(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf) {
	int x, y;

	for(y = 0; y < POU_MAT_Y; y++) {
		for(x = 0; x < POU_MAT_X; x++) {
			if(y == 0 || y == POU_MAT_Y - 1 || x == 0 || x == POU_MAT_X - 1) {
				matrix[x][y] = POU_MUR;
			}
			else {
				matrix[x][y] = POU_VIDE;
			}
		}
	}

	inf->coups = EMPTY_CONTAINER;
	inf->nb_caisses = 0;
	inf->nb_caisses_restantes = 0;
	inf->nb_trous = 0;
	inf->nb_deplacements = 0;
	inf->pos_inf.x = 0;
	inf->pos_inf.y = 0;
	inf->pos_joueur.x = -1;
	inf->pos_joueur.y = -1;
}
